#include "CameraLookat.h"
#include "Timer.h"
#include "InputManager.h"
#include "ScreenResolution.h"
#include "SceneManager.h"

CameraLookat::CameraLookat(void)
{
	m_position = Vector3(0, 0, 0);
	m_up = Vector3(0, 1, 0);
	m_fovY = PI/4;
	m_aspect = ScreenResolution::GetInstance()->GetScreenRatio();
	m_nearPlane = 0.1;
	m_farPlane = 500;
	m_speed = 1;
	CalculateProjectMatrix();
}

CameraLookat::~CameraLookat(void)
{
}

void CameraLookat::Init(GLfloat fovY, GLfloat aspect, GLfloat nearPlane, GLfloat farPlane, GLfloat speed)
{
	m_fovY = fovY;
	m_aspect = aspect;
	m_nearPlane = nearPlane;
	m_farPlane = farPlane;
	m_speed = speed;
	CalculateProjectMatrix();
}

Matrix CameraLookat::CalculateWorldMatrix()
{
	Vector3 zaxis = ( m_position - m_target ).Normalize();
	Vector3 xaxis = ( m_up.Cross( zaxis )).Normalize();
	Vector3 yaxis = ( zaxis.Cross( xaxis ) ).Normalize();

	Matrix rotationMatrix, translationMatrix;

	rotationMatrix.SetRightVector(xaxis);
	rotationMatrix.SetUpVector(yaxis);
	rotationMatrix.SetForwardVector(zaxis);
	rotationMatrix.SetTranslationVector(Vector3(0.0f, 0.0f, 0.0f));

	translationMatrix.SetTranslation( m_position );
	Matrix worldMatrix = rotationMatrix * translationMatrix;

	return worldMatrix;
}

void CameraLookat::CalculateProjectMatrix()
{
	m_projectMatrix.SetPerspective(m_fovY, m_aspect, m_nearPlane, m_farPlane);
}

Matrix CameraLookat::CalculateViewProjectMatrix()
{
	Matrix viewMatrix;
	viewMatrix.SetLookAt(m_position, m_target, m_up);

	Matrix viewProjectMatrix = viewMatrix * m_projectMatrix;
	return viewProjectMatrix;
}

void CameraLookat::Update()
{
	InputManager *inputManager = InputManager::GetInstance();

	if (inputManager->IsKeyDown(38))
	{
		Rotate(UP);
	}

	if (inputManager->IsKeyDown(37))
	{
		Rotate(LEFT);
	}

	if (inputManager->IsKeyDown(39))
	{
		Rotate(RIGHT);
	}

	if (inputManager->IsKeyDown(40))
	{
		Rotate(DOWN);
	}

	if (inputManager->IsKeyDown(65))
	{
		Move(LEFT);
	}

	if (inputManager->IsKeyDown(68))
	{
		Move(RIGHT);
	}

	if (inputManager->IsKeyDown(87))
	{
		Move(FORWARD);
	}

	if (inputManager->IsKeyDown(83))
	{
		Move(BACKWARD);
	}
}

void CameraLookat::Move(Direction direction)
{
	Vector3 zaxis = (m_position - m_target).Normalize();
	Vector3 xaxis = (m_up.Cross(zaxis)).Normalize();
	Vector3 deltaMove;
	switch (direction)
	{
		case FORWARD:
			deltaMove = - zaxis * Timer::FrameTime() * m_speed;
			break;
		case BACKWARD:
			deltaMove = zaxis * Timer::FrameTime() * m_speed;
			break;
		case RIGHT:
			deltaMove = xaxis * Timer::FrameTime() * m_speed;
			break;
		case LEFT:
			deltaMove = - xaxis * Timer::FrameTime() * m_speed;
			break;
	}
	m_position += deltaMove;
	m_target += deltaMove;
}

void CameraLookat::Rotate(Direction direction)
{
	Vector4 localTarget = Vector4(0, 0, -(m_position - m_target).Length(), 1);
	Matrix rotMatrix;
	switch (direction)
	{
		case UP:
			rotMatrix.SetRotationX(Timer::FrameTime() * m_speed);
			break;
		case DOWN:
			rotMatrix.SetRotationX(- Timer::FrameTime() * m_speed);
			break;
		case RIGHT:
			rotMatrix.SetRotationY(- Timer::FrameTime() * m_speed);
			break;
		case LEFT:
			rotMatrix.SetRotationY(Timer::FrameTime() * m_speed);
			break;
	}
	Vector4 localNewTarget = localTarget * rotMatrix;
	Vector4 worldNewTarget = localNewTarget * CalculateWorldMatrix();
	m_target = worldNewTarget.xyz;
}